import json
import os
from datetime import datetime
from app.models.database import db, TargetRange, Scan, Vulnerability
from app.utils.logger import logger

class InternalTargetRangeService:
    """
    内置靶场管理服务
    提供内置漏洞靶场的创建、管理和模拟功能
    """
    
    # 靶场场景配置
    TARGET_SCENARIOS = {
        "beginner-web": {
            "name": "初级Web安全靶场",
            "description": "适合初学者的基础Web安全漏洞练习环境",
            "difficulty": "beginner",
            "target_url": "http://localhost:8000/beginner",
            "vulnerabilities": [
                {"type": "xss", "path": "/search", "params": ["q"], "severity": "medium"},
                {"type": "sql_injection", "path": "/login", "params": ["username"], "severity": "high"},
                {"type": "info_leak", "path": "/backup/config.txt", "severity": "low"}
            ]
        },
        "intermediate-web": {
            "name": "中级Web安全靶场",
            "description": "包含中等难度漏洞的Web应用靶场",
            "difficulty": "intermediate",
            "target_url": "http://localhost:8000/intermediate",
            "vulnerabilities": [
                {"type": "command_injection", "path": "/admin/system", "params": ["cmd"], "severity": "high"},
                {"type": "path_traversal", "path": "/file/view", "params": ["file"], "severity": "high"},
                {"type": "csrf", "path": "/api/users/change-email", "severity": "medium"},
                {"type": "ssrf", "path": "/api/proxy", "params": ["url"], "severity": "high"}
            ]
        },
        "advanced-web": {
            "name": "高级Web安全靶场",
            "description": "包含复杂漏洞链和高级攻击技术的靶场",
            "difficulty": "advanced",
            "target_url": "http://localhost:8000/advanced",
            "vulnerabilities": [
                {"type": "insecure_deserialization", "path": "/api/data", "params": ["data"], "severity": "critical"},
                {"type": "broken_access_control", "path": "/api/admin", "severity": "high"},
                {"type": "ssl_tls_issues", "severity": "medium"},
                {"type": "cors_misconfiguration", "severity": "medium"},
                {"type": "ssrf", "path": "/api/internal/proxy", "params": ["endpoint"], "severity": "critical"}
            ]
        }
    }
    
    @staticmethod
    def get_available_scenarios():
        """
        获取所有可用的靶场场景
        """
        try:
            scenarios = []
            for scenario_id, config in InternalTargetRangeService.TARGET_SCENARIOS.items():
                scenarios.append({
                    "id": scenario_id,
                    "name": config["name"],
                    "description": config["description"],
                    "difficulty": config["difficulty"],
                    "target_url": config["target_url"],
                    "vulnerability_count": len(config["vulnerabilities"])
                })
            return scenarios
        except Exception as e:
            logger.error(f"Failed to get available scenarios: {str(e)}")
            return []
    
    @staticmethod
    def create_target_range_from_scenario(scenario_id, user_id):
        """
        从场景模板创建靶场配置
        """
        try:
            if scenario_id not in InternalTargetRangeService.TARGET_SCENARIOS:
                raise ValueError(f"Scenario {scenario_id} not found")
            
            scenario = InternalTargetRangeService.TARGET_SCENARIOS[scenario_id]
            
            # 创建靶场配置
            target_range = TargetRange(
                user_id=user_id,
                name=f"内置靶场 - {scenario['name']}",
                base_url=scenario['target_url'],
                auth_type="none",
                description=scenario['description'],
                tags=json.dumps(["internal", scenario['difficulty']]),
                is_active=True,
                last_connected=datetime.utcnow()
            )
            
            db.session.add(target_range)
            db.session.commit()
            
            logger.info(f"Created internal target range for scenario {scenario_id}: {target_range.id}")
            return target_range
        except Exception as e:
            logger.error(f"Failed to create target range from scenario {scenario_id}: {str(e)}")
            db.session.rollback()
            raise
    
    @staticmethod
    def simulate_scan(target_range_id, scan_depth=3):
        """
        模拟对靶场的扫描，生成预定的漏洞结果
        """
        try:
            # 获取靶场配置
            target_range = TargetRange.query.get(target_range_id)
            if not target_range:
                raise ValueError(f"Target range {target_range_id} not found")
            
            # 查找对应的场景
            scenario_id = None
            for sid, config in InternalTargetRangeService.TARGET_SCENARIOS.items():
                if target_range.base_url == config['target_url']:
                    scenario_id = sid
                    break
            
            if not scenario_id:
                raise ValueError("No matching scenario found for this target range")
            
            scenario = InternalTargetRangeService.TARGET_SCENARIOS[scenario_id]
            
            # 创建扫描任务
            scan = Scan(
                target=target_range.base_url,
                scan_depth=scan_depth,
                created_by=target_range.user_id,
                status="completed",
                started_at=datetime.utcnow(),
                finished_at=datetime.utcnow()
            )
            db.session.add(scan)
            db.session.flush()
            
            # 生成漏洞结果
            vulnerabilities = []
            for vuln_config in scenario['vulnerabilities']:
                # 根据扫描深度过滤漏洞
                if scan_depth < 3 and vuln_config.get('severity') == 'critical':
                    continue
                
                vuln = Vulnerability(
                    scan_id=scan.id,
                    vuln_type=vuln_config['type'],
                    path=vuln_config.get('path', '/'),
                    params=json.dumps(vuln_config.get('params', [])),
                    severity=vuln_config['severity'],
                    confidence=0.95,
                    risk_score=InternalTargetRangeService._get_risk_score(vuln_config['severity']),
                    description=InternalTargetRangeService._get_vulnerability_description(vuln_config),
                    evidence=f"靶场模拟漏洞 - {vuln_config['type']}",
                    created_at=datetime.utcnow()
                )
                vulnerabilities.append(vuln)
            
            db.session.add_all(vulnerabilities)
            db.session.commit()
            
            logger.info(f"Simulated scan completed for target range {target_range_id}, found {len(vulnerabilities)} vulnerabilities")
            return scan
        except Exception as e:
            logger.error(f"Failed to simulate scan for target range {target_range_id}: {str(e)}")
            db.session.rollback()
            raise
    
    @staticmethod
    def _get_risk_score(severity):
        """根据严重程度获取风险分数"""
        scores = {
            "low": 0.3,
            "medium": 0.6,
            "high": 0.8,
            "critical": 0.95
        }
        return scores.get(severity, 0.5)
    
    @staticmethod
    def _get_vulnerability_description(vuln_config):
        """获取漏洞描述"""
        descriptions = {
            "xss": "跨站脚本漏洞允许攻击者在用户浏览器中执行恶意脚本。",
            "sql_injection": "SQL注入漏洞允许攻击者执行恶意SQL语句，可能导致数据泄露或数据库被篡改。",
            "info_leak": "信息泄露漏洞可能暴露敏感的系统信息给未授权用户。",
            "command_injection": "命令注入漏洞允许攻击者在服务器上执行任意系统命令。",
            "path_traversal": "路径遍历漏洞允许攻击者访问服务器上的敏感文件。",
            "csrf": "跨站请求伪造漏洞允许攻击者诱导用户执行非预期的操作。",
            "ssrf": "服务器端请求伪造漏洞允许攻击者诱导服务器发起请求到攻击者指定的目标。",
            "insecure_deserialization": "不安全的反序列化可能导致远程代码执行。",
            "broken_access_control": "访问控制缺陷允许未授权用户访问受保护的资源。",
            "ssl_tls_issues": "SSL/TLS配置问题可能导致通信不安全。",
            "cors_misconfiguration": "CORS配置错误可能导致跨域安全问题。"
        }
        
        vuln_type = vuln_config['type']
        desc = descriptions.get(vuln_type, "该漏洞可能导致安全风险。")
        
        if 'path' in vuln_config:
            desc += f" 漏洞位于 {vuln_config['path']} 路径。"
        
        if 'params' in vuln_config and vuln_config['params']:
            desc += f" 受影响的参数: {', '.join(vuln_config['params'])}"
        
        return desc
    
    @staticmethod
    def get_scoring_guide(scenario_id):
        """
        获取靶场评分指南
        """
        try:
            if scenario_id not in InternalTargetRangeService.TARGET_SCENARIOS:
                raise ValueError(f"Scenario {scenario_id} not found")
            
            scenario = InternalTargetRangeService.TARGET_SCENARIOS[scenario_id]
            
            # 计算满分
            total_score = 0
            scoring_items = []
            
            for vuln in scenario['vulnerabilities']:
                score = InternalTargetRangeService._get_severity_score(vuln['severity'])
                total_score += score
                scoring_items.append({
                    "vulnerability_type": vuln['type'],
                    "path": vuln.get('path', 'N/A'),
                    "severity": vuln['severity'],
                    "score": score,
                    "description": InternalTargetRangeService._get_vulnerability_description(vuln)
                })
            
            return {
                "scenario_id": scenario_id,
                "scenario_name": scenario['name'],
                "total_possible_score": total_score,
                "scoring_items": scoring_items,
                "grading_scale": {
                    "A": f">= {total_score * 0.9:.1f}",
                    "B": f">= {total_score * 0.7:.1f} - < {total_score * 0.9:.1f}",
                    "C": f">= {total_score * 0.5:.1f} - < {total_score * 0.7:.1f}",
                    "D": f">= {total_score * 0.3:.1f} - < {total_score * 0.5:.1f}",
                    "F": f">= 0 - < {total_score * 0.3:.1f}"
                }
            }
        except Exception as e:
            logger.error(f"Failed to get scoring guide for scenario {scenario_id}: {str(e)}")
            raise
    
    @staticmethod
    def _get_severity_score(severity):
        """根据严重程度获取分数"""
        scores = {
            "low": 10,
            "medium": 25,
            "high": 50,
            "critical": 100
        }
        return scores.get(severity, 25)